package chen.yi.service.utils;
import chen.yi.common.constant.TokenConstant;
import chen.yi.common.enums.StatusEnum;
import chen.yi.mapper.base.BasePO;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 公共字段自动赋值工具类（JDK17优化版）
 * 使用VarHandle替代传统反射，提升字段操作性能
 */
public final class UserRequestUtils {
    private UserRequestUtils() {

    }

    /**
     * 公共字段集合 key 字段名称 value 字段类型
     */
    private final static Map<String,Object> BASE_FIELD=new ConcurrentHashMap<>();

    static {
        Class<BasePO> basePOClass = BasePO.class;
        Field[] declaredFields = basePOClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            BASE_FIELD.put(declaredField.getName(), declaredField.getType());

        }
    }


    // 使用ConcurrentHashMap缓存各类的字段处理器，键为Class对象，值为字段名-VarHandle的映射
    private static final Map<Class<?>, Map<String, VarHandle>> HANDLE_CACHE = new ConcurrentHashMap<>();

    // MethodHandles.Lookup实例用于获取VarHandle
    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

    /**
     * 设置对象公共字段值
     * @param target 目标对象实例
     * @param flag 操作模式：true-设置全部公共字段，false-仅设置修改相关字段
     */
    public static void setBaseInfo(Object target, boolean flag) {
        if (target == null) return;

        // 获取目标对象的Class对象
        Class<?> clazz = target.getClass();

        // 从缓存获取或创建字段处理器映射
        Map<String, VarHandle> handles = HANDLE_CACHE.computeIfAbsent(clazz, k -> {
            try {
                // 获取私有字段访问权限
                var privateLookup = MethodHandles.privateLookupIn(clazz, LOOKUP);
                Map<String, VarHandle> map = new ConcurrentHashMap<>();

                // 预加载所有可能存在的字段处理器（忽略不存在的字段）
                BASE_FIELD.forEach((fieldName,fieldType) -> {
                    putIfExists(privateLookup, map, clazz, "fieldName", fieldType.getClass());
                });
                return map;
            } catch (Exception e) {
                throw new RuntimeException("初始化VarHandle失败", e);
            }
        });

        LocalDateTime timestamp = LocalDateTime.now();
        //获取requestAttributes
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 获取请求上下文
        HttpServletRequest request = requestAttributes.getRequest();
        String header = request.getHeader(TokenConstant.TOKEN_KEY);
        JWT jwt = JWTUtil.parseToken(header);
        Long id = (Long)jwt.getPayload("id");
        String realName = (String)jwt.getPayload("realName");
        try {
            if (flag) {
                // 全量模式：设置状态、创建时间和修改时间
                setIfPresent(handles, target, "status", StatusEnum.VALID.getCode());
                setIfPresent(handles, target, "createId", id);
                setIfPresent(handles, target, "createName",realName);
                setIfPresent(handles, target, "createTime", timestamp);
                setIfPresent(handles, target, "deleteFlag", "N");
            }
                // 精简模式：仅设置修改时间
                setIfPresent(handles, target, "updateId", id);
                setIfPresent(handles, target, "updateName", realName);
                setIfPresent(handles, target, "updateTime", timestamp);

        } catch (Exception e) {
            throw new RuntimeException("字段赋值失败", e);
        }
    }

    /**
     * 安全获取字段VarHandle并存入缓存
     * @param lookup 方法查找器
     * @param map 字段处理器映射
     * @param clazz 目标类
     * @param fieldName 字段名
     * @param type 字段类型
     */
    private static void putIfExists(MethodHandles.Lookup lookup, Map<String, VarHandle> map,
                                    Class<?> clazz, String fieldName, Class<?> type) {
        try {
            // 尝试获取字段VarHandle并存入缓存
            map.put(fieldName, lookup.findVarHandle(clazz, fieldName, type));
        } catch (NoSuchFieldException ignored) {
            // 忽略不存在的字段（允许类缺少部分字段）
        } catch (Exception e) {
            throw new RuntimeException("字段处理异常: " + fieldName, e);
        }
    }

    /**
     * 安全设置字段值
     * @param handles 字段处理器映射
     * @param target 目标对象
     * @param fieldName 字段名
     * @param value 要设置的值
     */
    private static void setIfPresent(Map<String, VarHandle> handles, Object target,
                                     String fieldName, Object value) {
        VarHandle handle = handles.get(fieldName);
        if (handle != null) {
            // 使用VarHandle进行线程安全的字段赋值
            handle.set(target, value);
        }
    }
}

